package com.niiwoo.civet.trade.service.local.loan;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dangdang.ddframe.rdb.sharding.api.HintManager;
import com.dangdang.ddframe.rdb.sharding.hint.HintManagerHolder;
import com.niiwoo.activity.event.enums.UsableCreditChangeTypeEventEnum;
import com.niiwoo.activity.stage.enums.prize.UserPrizeSuitProjectTypeEnum;
import com.niiwoo.asset.cardniu.dto.mq.CardNiuExternalMQConstants;
import com.niiwoo.asset.cardniu.dto.request.LoanStatusDTO;
import com.niiwoo.asset.constant.MqConstants;
import com.niiwoo.asset.dto.mq.R360OrderStatusChangedDTO;
import com.niiwoo.asset.enums.r360.R360OrderProjectSubStatusEnum;
import com.niiwoo.asset.enums.r360.R360OrderStatusEnum;
import com.niiwoo.civet.base.enums.DeadlineUnitEnum;
import com.niiwoo.civet.trade.constant.MqConstant;
import com.niiwoo.civet.trade.constant.RabbitConstant;
import com.niiwoo.civet.trade.dao.entity.*;
import com.niiwoo.civet.trade.dao.mapper.*;
import com.niiwoo.civet.trade.dto.AddAuditWorkTaskReqDTO;
import com.niiwoo.civet.trade.dto.BorrowPrizeOccupyDTO;
import com.niiwoo.civet.trade.dto.common.ProjectDynamicDTO;
import com.niiwoo.civet.trade.dto.request.AddInterestRateConfigRequestDTO;
import com.niiwoo.civet.trade.dto.request.SpeedLoanApplyForBackRequestDTO;
import com.niiwoo.civet.trade.dto.request.SpeedLoanApplyRequestDTO;
import com.niiwoo.civet.trade.dto.request.SpeedLoanPublishCheckRequestDTO;
import com.niiwoo.civet.trade.dto.request.contract.WithholdContractSignMQDTO;
import com.niiwoo.civet.trade.dto.request.databackflow.ProjectStatusChangeBackFlowRequestDTO;
import com.niiwoo.civet.trade.dto.request.loan.PushProjectRequestDTO;
import com.niiwoo.civet.trade.dto.response.AddInterestRateConfigResponseDTO;
import com.niiwoo.civet.trade.dto.response.SpeedLoanApplyCommonResponseDTO;
import com.niiwoo.civet.trade.dto.response.SpeedLoanConfigurationResponseDTO;
import com.niiwoo.civet.trade.dto.response.SpeedLoanQueryResponseDTO;
import com.niiwoo.civet.trade.enums.*;
import com.niiwoo.civet.trade.service.local.activity.ActivityEventService;
import com.niiwoo.civet.trade.service.local.common.ProjectCommonService;
import com.niiwoo.civet.trade.service.local.configure.TradeConfigLocalService;
import com.niiwoo.civet.trade.service.local.databackflow.TianChengDataBackFlowLocalService;
import com.niiwoo.civet.trade.service.local.invest.InvestService;
import com.niiwoo.civet.trade.service.local.invest.ProjectInvestPrizeService;
import com.niiwoo.civet.trade.service.local.project.ProjectLocalService;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import com.niiwoo.tripod.tiancheng.component.TianchengAgainstFakeService;
import com.niiwoo.tripod.tiancheng.request.afp.SpeedLoanCreditAuditRequest;
import com.niiwoo.tripod.tiancheng.response.common.AgainstFakeResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.time.FastDateFormat;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * @Description:
 * @Author:LiJian
 * @Date:2017/11/8
 */
@Slf4j
@Service
public class SpeedLoanService {
    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;
    @Autowired
    private ProjectMapperExt projectMapper;
    @Autowired
    private ProjectBorrowerSummaryMapperExt projectBorrowerSummaryMapper;
    @Autowired
    private ProjectLoanRateConfigMapperExt projectLoanRateConfigMapper;
    @Autowired
    private ProjectLoanDeadlineConfigMapperExt projectLoanDeadlineConfigMapper;
    @Autowired
    private ProjectLoanDeviceInfoMapperExt projectLoanDeviceInfoMapper;
    @Autowired
    private TradeConfigLocalService tradeConfigService;
    @Autowired
    private ProjectCommonService projectCommonService;
    @Autowired
    private AutoAuditModelResultMapperExt autoAuditModelResultMapper;
    @Autowired
    private AutoAuditModelResultRecordMapper autoAuditModelResultRecordMapper;
    @Autowired
    private ProjectPushRecordMapperExt projectPushRecordMapper;
    @Autowired
    private ProjectAuditDecisionMapperExt projectAuditDecisionMapper;
    @Autowired
    private ProjectBorrowerPrizeOccupyRecordMapperExt projectBorrowerPrizeOccupyRecordMapper;
    @Autowired
    private AddressListWaitBackflowRecordMapperExt addressListWaitBackflowRecordMapper;
    @Autowired
    private InvestService investService;
    @Autowired
    private CallRiskRuleRecordMapperExt callRiskRuleRecordMapper;
    @Autowired
    private SpeedLoanRateConfigService speedLoanRateConfigService;
    @Autowired
    private ProjectRateMapperExt projectRateMapper;
    @Autowired
    private RateConfigPercentMapperExt rateConfigPercentMapper;
    @Autowired
    private ProjectLocalService projectLocalService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private ProjectBackoutBorrowPrizeMapperExt projectBackoutBorrowPrizeMapperExt;
    @Autowired
    private ProjectAuditConfigMapperExt projectAuditConfigMapperExt;
    @Autowired
    private TianChengDataBackFlowLocalService tianChengDataBackFlowLocalService;
    @Autowired
    private ActivityEventService activityEventService;
    @Autowired
    private TianchengAgainstFakeService tianchengAgainstFakeService;
    
    @Autowired
    private ProjectInvestPrizeService projectInvestPrizeService;

    @Autowired
    private NewbieProjectConfigMapperExt newbieProjectConfigMapper;


    /**
     * 获取用户已使用额度
     *
     * @param userId
     * @return
     */
    public BigDecimal getSpeedUsedCredit(String userId) {
        List<Byte> statusList = new ArrayList<>();
        // 只统计审核中、募集中、还款中的借款金额
        statusList.add(ProjectStatusEnum.CHECKING.getStatus());
        statusList.add(ProjectStatusEnum.COLLECTING.getStatus());
        statusList.add(ProjectStatusEnum.REPAYING.getStatus());
        BigDecimal speedUsedCredit = projectMapper.statisticsLoanAmountByStatus(userId, statusList, null, ProjectTypeEnum.PERSONAL_SPEEDLOAN.getValue());
        speedUsedCredit = (speedUsedCredit == null ? BigDecimal.ZERO : speedUsedCredit);
        // 减去已退回标的金额
        List<Integer> subStatusList = new ArrayList<>();
        subStatusList.add(ProjectSubStatusEnum.CHECKING_BACK.getSubStatus());
        subStatusList.add(ProjectSubStatusEnum.CHECKING_BACK_PHONEOPERATOR_TIMEOUT.getSubStatus());
        subStatusList.add(ProjectSubStatusEnum.CHECKING_BACK_ADDRESSLIST_TIMEOUT.getSubStatus());
        BigDecimal backAmount = projectMapper.statisticsLoanAmountByStatus(userId, null, subStatusList, ProjectTypeEnum.PERSONAL_SPEEDLOAN.getValue());
        backAmount = (backAmount == null ? BigDecimal.ZERO : backAmount);

        return speedUsedCredit.subtract(backAmount);
    }

    /**
     * 更新标的状态
     * @param projectId
     * @param projectStatusEnum
     * @param projectSubStatusEnum
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateProjectStatus(Long projectId,ProjectStatusEnum projectStatusEnum,ProjectSubStatusEnum projectSubStatusEnum) {
        Project project2Update=new Project();
        project2Update.setProjectId(projectId);
        if(projectStatusEnum!=null) {
            project2Update.setStatus(projectStatusEnum.getStatus());
        }
        project2Update.setSubStatus(projectSubStatusEnum.getSubStatus());
        project2Update.setUpdateTime(new Date());

        projectMapper.updateByPrimaryKeySelective(project2Update);
        log.info("标的ID={},已更新标的状态={},标的子状态={}.", projectId, projectStatusEnum, projectSubStatusEnum);
    }

    private String createForbidTip(Date Time) {
        FastDateFormat fdf = FastDateFormat.getInstance("yyyy年MM月dd日");
        StringBuilder tipSb = new StringBuilder();
        tipSb.append("抱歉，您的综合信用评分不足，暂时无法借钱，请于");
        tipSb.append(fdf.format(Time));
        tipSb.append("后再来申请");

        return tipSb.toString();
    }

    //标的数据检查
    public void speedLoanPublishCheck_projectCheck(SpeedLoanPublishCheckRequestDTO requestDTO, SpeedLoanApplyCommonResponseDTO resposeDTO) {
        String userId = requestDTO.getUserId();
        log.info("speedLoanPublishCheck_hisProjectCheck.userId={} start",userId);

        //检查当前是否存在逾期未还标的
        this.speedLoanPublishCheck_projectCheck_overdue(requestDTO,resposeDTO);
        //用户借款历史记录中出现30天以上还款逾期 系统提示“综合评分不足”，予以拒绝
        this.speedLoanPublishCheck_projectCheck_hisOverdue30Day(requestDTO,resposeDTO);
        //检查当前是否存在退回标的
        this.speedLoanPublishCheck_projectCheck_back(requestDTO,resposeDTO);
        //检查当前是否存在审核中标的
        this.getSelfProxy().speedLoanPublishCheck_projectCheck_auditing(requestDTO,resposeDTO);

        log.info("speedLoanPublishCheck_hisProjectCheck.userId={} end",userId);
    }

    //检查当前是否存在逾期未还标的
    private void speedLoanPublishCheck_projectCheck_overdue(SpeedLoanPublishCheckRequestDTO requestDTO, SpeedLoanApplyCommonResponseDTO resposeDTO) {
        String userId = requestDTO.getUserId();
        // 当前用户存在逾期未还的借款
        int overdueProjectCount = projectMapper.statisticsProjectCountByStatus(userId, Arrays.asList(ProjectStatusEnum.REPAYING.getStatus()), Arrays.asList(ProjectSubStatusEnum.REPAYING_OVERDUE.getSubStatus(), ProjectSubStatusEnum.REPAYING_BAD.getSubStatus()));
        log.info("speedLoanPublishCheck_projectCheck_overdue.userId={},overdueProjectCount={}",userId,overdueProjectCount);
        if (overdueProjectCount > 0) {
            // 有逾期坏账借款标！（信用借或极速借）
            this.speedLoanPublishCheck_excetipnResponseDeal(LoanLimitMessageEnum.LIMIT_10008, resposeDTO);
        }
    }

    //检查是否有历史记录中出现30天以上还款逾期标的
    private void speedLoanPublishCheck_projectCheck_hisOverdue30Day(SpeedLoanPublishCheckRequestDTO requestDTO, SpeedLoanApplyCommonResponseDTO resposeDTO) {
        String userId = requestDTO.getUserId();
		int countOverdueDayOver30d = projectMapper.statisticsUserOverdueExceedDay(userId, 30);
        log.info("speedLoanPublishCheck_projectCheck_hisOverdue30Day.userId={},countOverdueDayOver30d={}",userId,countOverdueDayOver30d);
        if (countOverdueDayOver30d > 0) {
            //暂被限制申请借款
            //this.speedLoanPublishCheck_excetipnResponseDeal(LoanLimitMessageEnum.LIMIT_10017, resposeDTO);
            resposeDTO.setStatus(LoanLimitMessageEnum.LIMIT_10017.getLimitCode());
            resposeDTO.setAlertTitle(LoanLimitMessageEnum.LIMIT_10017.getLimitMessageTitle());
            String limitMessageDesc = "抱歉，您的综合信用评分不足，暂时无法借钱。\n\n如有疑问，请联系钱小二！";
            resposeDTO.setAlertDesc(limitMessageDesc);
            throw new BizException("TRD10006",limitMessageDesc);
        }
    }

    //检查当前是否存在退回标的
    private void speedLoanPublishCheck_projectCheck_back(SpeedLoanPublishCheckRequestDTO requestDTO, SpeedLoanApplyCommonResponseDTO resposeDTO) {
        String userId = requestDTO.getUserId();
        //退回检查---必须在“审核中、待确认借款检查”之前，因为审核中状态包含退回状态
        if(ProjectApplyCheckTypeEnum.BACK_PROJ_SUBMIT_CHECK.getCheckType()==requestDTO.getProjectApplyCheckTypeEnum().getCheckType()) {
            return;
        }

        Project backProject = projectMapper.speedLoanQueryForBack(userId);
        log.info("speedLoanPublishCheck_projectCheck_back.userId={},backProject={}",userId,JSON.toJSONString(backProject));

        if (backProject == null) {
            return;
        }

        Map extendData = new HashMap();
        extendData.put("projectId",backProject.getProjectId());
        extendData.put("projectTitle",backProject.getTitle());
        Date createTime = backProject.getCreateTime();
        String createTimeStr = createTime==null?null:(FastDateFormat.getInstance("yyyy-MM-dd").format(backProject.getCreateTime()));
        extendData.put("projectAddDate",createTimeStr);
        extendData.put("fromSource",backProject.getFromSource());
        resposeDTO.setExtendData(extendData);
        //有借款标处于退回状态！
        this.speedLoanPublishCheck_excetipnResponseDeal(LoanLimitMessageEnum.LIMIT_10012, resposeDTO);
    }

    //检查当前是否存在审核中标的
    @Transactional
    public void speedLoanPublishCheck_projectCheck_auditing(SpeedLoanPublishCheckRequestDTO requestDTO, SpeedLoanApplyCommonResponseDTO resposeDTO) {
        String userId = requestDTO.getUserId();
        //审核中、待确认借款检查
        int auditingProjectCount = projectMapper.statisticsProjectCountByStatus(
                userId, Arrays.asList(ProjectStatusEnum.CHECKING.getStatus()),
                Arrays.asList(ProjectSubStatusEnum.CHECKING_INIT.getSubStatus(),
                        ProjectSubStatusEnum.CHECKING_LOAN_FAKE_PASS.getSubStatus(),
                        ProjectSubStatusEnum.CHECKING_AUTO_SUCCESS.getSubStatus(),
                        ProjectSubStatusEnum.CHECKING_AUTO_MANUAL.getSubStatus(),
                        ProjectSubStatusEnum.CHECKING_MANUAL_SUCCESS.getSubStatus(),
                        ProjectSubStatusEnum.CHECKING_FOR_CONFIRM.getSubStatus())
        );
        log.info("speedLoanPublishCheck_projectCheck_auditing.userId={},auditingProjectCount={}",userId,auditingProjectCount);
        if (auditingProjectCount > 0) {
            // 有借款标在审核中！
            this.speedLoanPublishCheck_excetipnResponseDeal(LoanLimitMessageEnum.LIMIT_10006, resposeDTO);
        }
    }

    //异常结果处理
    public void speedLoanPublishCheck_excetipnResponseDeal(LoanLimitMessageEnum loanLimitMessageEnum, SpeedLoanApplyCommonResponseDTO resposeDTO) {
        resposeDTO.setStatus(loanLimitMessageEnum.getLimitCode());
        resposeDTO.setAlertTitle(loanLimitMessageEnum.getLimitMessageTitle());
        String limitMessageDesc = loanLimitMessageEnum.getLimitMessageDesc();
        resposeDTO.setAlertDesc(limitMessageDesc);
        throw new BizException("TRD10006",limitMessageDesc);
    }

    public SpeedLoanConfigurationResponseDTO speedLoanConfiguration(String userId, BigDecimal aviAmount) {
        log.info("SpeedLoanService.getSpeedLoanRateConfig userId={},aviAmount={} start",userId,aviAmount);
        //获取用户极速借风险定价费率配置
        SpeedLoanConfigurationResponseDTO responseDTO = speedLoanRateConfigService.getSpeedLoanRateConfig(aviAmount);
        return responseDTO;
    }

    private List<Integer> getDealLineList(String deadLineConfig){
        if (!StringUtils.hasText(deadLineConfig)) {
            return null;
        }
        String[] dealLineArray = deadLineConfig.split(",");
        if(dealLineArray==null || dealLineArray.length==0){
            return null;
        }
        List<Integer> deadLineList = new ArrayList<>();
        for(int i=0;i<dealLineArray.length;i++){
            String dealLine = dealLineArray[i];
            deadLineList.add(Integer.valueOf(dealLine));
        }
        return deadLineList;
    }

    /**
     * 极速借配置信息检查
     * @param speedLoanApplyRequestDTO
     * @param resposeDTO
     */
    public void speedLoanConfigurationCheck(SpeedLoanApplyRequestDTO speedLoanApplyRequestDTO, SpeedLoanApplyCommonResponseDTO resposeDTO) {
        String userId = speedLoanApplyRequestDTO.getUserId();
        BigDecimal loanAmount = speedLoanApplyRequestDTO.getLoanAmount(); //借款金额
        log.info("speedLoanConfigurationCheck.userId={},loanAmount=={} start",userId,loanAmount);
        List<ProjectRateConfig> rateConfigList = speedLoanRateConfigService.getRateConfigByLoanAmount(loanAmount);
        log.info("speedLoanConfigurationCheck.userId={},loanAmount=={},rateConfigList={}",userId,loanAmount,JSON.toJSONString(rateConfigList));
        if(CollectionUtils.isEmpty(rateConfigList)){
            //借款期限不在后台配置限制范围内
            this.speedLoanPublishCheck_excetipnResponseDeal(LoanLimitMessageEnum.LIMIT_10041, resposeDTO);
        }

        Integer chooseDeadline = speedLoanApplyRequestDTO.getDeadline(); //用户选择的借款期限
        List<Integer> deadlineList = speedLoanRateConfigService.getLoanDeadlineListByLoanAmount(loanAmount);
        log.info("speedLoanConfigurationCheck.userId={},loanAmount=={},deadlineList={}",userId,loanAmount,JSON.toJSONString(deadlineList));
        if(CollectionUtils.isEmpty(deadlineList) || !deadlineList.contains(chooseDeadline)){
            //借款期限不在后台配置限制范围内
            this.speedLoanPublishCheck_excetipnResponseDeal(LoanLimitMessageEnum.LIMIT_10042, resposeDTO);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void loanProjectRelateInfoCreat(SpeedLoanApplyRequestDTO speedLoanApplyRequestDTO, Project insertProject) {
        log.info("loanProjectRelateInfoCreat.insertProject={}",JSON.toJSONString(insertProject));
        String userId = speedLoanApplyRequestDTO.getUserId();
        Long projectId = insertProject.getProjectId();
        projectMapper.insertSelective(insertProject);

        //插入设备信息
        this.projectLoanDeviceInfoCreat(speedLoanApplyRequestDTO,insertProject);

        //插入通讯录信息
        this.addressListWaitBackflowRecordCreat(speedLoanApplyRequestDTO,insertProject);

        //插入标的费率数据
        projectRateCreat(userId,projectId,speedLoanApplyRequestDTO.getDeadline());

        ProjectDynamicDTO projectDynamicDTO = new ProjectDynamicDTO();
        projectDynamicDTO.setUserId(userId);
        projectDynamicDTO.setProjectId(projectId);
        projectDynamicDTO.setTradeTypeEnum(ProjectDynamicDTO.TradeTypeEnum.REPAYMENT);
        projectDynamicDTO.setProjectDynamicEnum(ProjectDynamicEnum.APPLY_SUBMIT_SUCCESS);
        projectLocalService.addProjectDynamicRecord(projectDynamicDTO);

        //发标信用额度变更消息推送
        sendMsgForAviAmountChange(insertProject.getBorrowUserId());
    }

    public void projectLoanDeviceInfoCreat(SpeedLoanApplyRequestDTO speedLoanApplyRequestDTO, Project project){
        SpeedLoanApplyRequestDTO.DeviceInfoRequestDTO deviceInfoRequestDTO = speedLoanApplyRequestDTO.getDeviceInfo();
        ProjectLoanDeviceInfo deviceInfo = new ProjectLoanDeviceInfo();
        BeanUtils.copyProperties(deviceInfoRequestDTO, deviceInfo);
        deviceInfo.setUserId(project.getBorrowUserId());
        deviceInfo.setProjectId(project.getProjectId());
        deviceInfo.setCreateTime(project.getCreateTime());
        deviceInfo.setUpdateTime(project.getUpdateTime());
        projectLoanDeviceInfoMapper.insertSelective(deviceInfo);
    }

    private void addressListWaitBackflowRecordCreat(SpeedLoanApplyRequestDTO speedLoanApplyRequestDTO,Project project){
        if(ProjectFromSourceEnum.R360.getType().byteValue()==speedLoanApplyRequestDTO.getFromSource().byteValue()) {
            //1.在正常发布标的时新增/退回重新提交标的时修改 风险规则待调用记录;
            ((SpeedLoanService)AopContext.currentProxy()).addOrUpdateCallRiskRuleRecord(project.getProjectId());
            return;
        }
        SpeedLoanApplyRequestDTO.DeviceInfoRequestDTO deviceInfoRequestDTO = speedLoanApplyRequestDTO.getDeviceInfo();
        List<SpeedLoanApplyRequestDTO.AddressInfoRequestDTO> addressInfoDTOList = speedLoanApplyRequestDTO.getAddressInfoDTOList();
        AddressListWaitBackflowRecord addressListWaitBackflowRecord = new AddressListWaitBackflowRecord();
        addressListWaitBackflowRecord.setProjectId(project.getProjectId());
        addressListWaitBackflowRecord.setUserId(project.getBorrowUserId());
        addressListWaitBackflowRecord.setDeviceId(deviceInfoRequestDTO.getDeviceId());
        addressListWaitBackflowRecord.setOs(deviceInfoRequestDTO.getOs());
        Byte deviceStatus = deviceInfoRequestDTO.getDeviceStatus();
        addressListWaitBackflowRecord.setEquipmentStatus(deviceStatus==null?0:deviceStatus);
        String addressInfoListJSONString = JSON.toJSONString(addressInfoDTOList);
        try {
            addressListWaitBackflowRecord.setAddressList(Base64.encodeBase64URLSafeString(addressInfoListJSONString.getBytes("UTF-8")));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        addressListWaitBackflowRecord.setCreateTime(project.getCreateTime());
        addressListWaitBackflowRecord.setUpdateTime(project.getUpdateTime());
        addressListWaitBackflowRecordMapper.insert(addressListWaitBackflowRecord);
    }

    @Transactional(rollbackFor = Exception.class)
    public void loanProjectRelateInfoUpdate(SpeedLoanApplyForBackRequestDTO speedLoanApplyForBackRequestDTO, Project updateProject) {
        //更新标的信息
        String userId = speedLoanApplyForBackRequestDTO.getUserId();
        Long projectId = speedLoanApplyForBackRequestDTO.getProjectId();
        updateProject.setProjectId(projectId);
        updateProject.setBorrowUserId(userId);
        updateProject.setCreateTime(null);
        projectMapper.updateForBackProject(updateProject);

        //更新设备信息
        projectLoanDeviceInfoUpdate(speedLoanApplyForBackRequestDTO,updateProject);

        //插入通讯录信息
        addressListWaitBackflowRecordUpdate(speedLoanApplyForBackRequestDTO,updateProject);

        //插入标的费率数据
        projectRateCreat(userId,projectId,speedLoanApplyForBackRequestDTO.getDeadline());

        ProjectDynamicDTO projectDynamicDTO = new ProjectDynamicDTO();
        projectDynamicDTO.setUserId(userId);
        projectDynamicDTO.setProjectId(projectId);
        projectDynamicDTO.setTradeTypeEnum(ProjectDynamicDTO.TradeTypeEnum.REPAYMENT);
        projectDynamicDTO.setProjectDynamicEnum(ProjectDynamicEnum.APPLY_SUBMIT_SUCCESS);
        projectLocalService.addProjectDynamicRecord(projectDynamicDTO);

        this.deleteAutoAuditModel(userId,projectId);


        //发标信用额度变更消息推送
        sendMsgForAviAmountChange(updateProject.getBorrowUserId());
    }

    private void deleteAutoAuditModel(String userId,Long projectId){
        Optional.ofNullable(autoAuditModelResultMapper.selectByProjectIdAndUserId(userId,projectId))
                .ifPresent(list->{
                    list.forEach(autoAuditModelResult->autoAuditModelResultMapper.deleteAutoAuditModel(
                            autoAuditModelResult.getId(),
                            userId,
                            projectId
                    ));
                });
    }

    private void projectLoanDeviceInfoUpdate(SpeedLoanApplyForBackRequestDTO speedLoanApplyForBackRequestDTO,Project project){
        SpeedLoanApplyForBackRequestDTO.DeviceInfoRequestDTO deviceInfoRequestDTO = speedLoanApplyForBackRequestDTO.getDeviceInfo();
        ProjectLoanDeviceInfo deviceInfo = new ProjectLoanDeviceInfo();
        BeanUtils.copyProperties(deviceInfoRequestDTO, deviceInfo);
        deviceInfo.setUserId(project.getBorrowUserId());
        deviceInfo.setProjectId(project.getProjectId());
        deviceInfo.setUpdateTime(project.getUpdateTime());
        projectLoanDeviceInfoMapper.updateByUserIdAndProjectSelective(deviceInfo);
    }

    private void addressListWaitBackflowRecordUpdate(SpeedLoanApplyForBackRequestDTO speedLoanApplyForBackRequestDTO,Project project){
        if(ProjectFromSourceEnum.R360.getType().byteValue()==speedLoanApplyForBackRequestDTO.getFromSource().byteValue()) {
            //1.在正常发布标的时新增/退回重新提交标的时修改 风险规则待调用记录;
            ((SpeedLoanService)AopContext.currentProxy()).addOrUpdateCallRiskRuleRecord(project.getProjectId());
            return;
        }
        Date now = new Date();
        String userId = project.getBorrowUserId();
        Long projectId = project.getProjectId();
        List<SpeedLoanApplyRequestDTO.AddressInfoRequestDTO> addressInfoDTOList = speedLoanApplyForBackRequestDTO.getAddressInfoDTOList();
        SpeedLoanApplyForBackRequestDTO.DeviceInfoRequestDTO deviceInfoRequestDTO = speedLoanApplyForBackRequestDTO.getDeviceInfo();
        AddressListWaitBackflowRecord addressListWaitBackflowRecord = new AddressListWaitBackflowRecord();
        addressListWaitBackflowRecord.setProjectId(projectId);
        addressListWaitBackflowRecord.setUserId(userId);
        addressListWaitBackflowRecord.setDeviceId(deviceInfoRequestDTO.getDeviceId());
        addressListWaitBackflowRecord.setOs(deviceInfoRequestDTO.getOs());
        Byte deviceStatus = deviceInfoRequestDTO.getDeviceStatus();
        addressListWaitBackflowRecord.setEquipmentStatus(deviceStatus==null?0:deviceStatus);

        String addressInfoListJSONString = JSON.toJSONString(addressInfoDTOList);
        try {
            addressListWaitBackflowRecord.setAddressList(Base64.encodeBase64URLSafeString(addressInfoListJSONString.getBytes("UTF-8")));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        addressListWaitBackflowRecord.setCreateTime(now);
        addressListWaitBackflowRecord.setUpdateTime(now);

        int existCount = addressListWaitBackflowRecordMapper.selectCountByUserIdProjectId(userId,projectId);
        if(existCount==0){
            addressListWaitBackflowRecordMapper.insertSelective(addressListWaitBackflowRecord);
        }else {
            addressListWaitBackflowRecordMapper.updateByUserIdAndProjectSelective(addressListWaitBackflowRecord);
        }
    }

    private void projectRateCreat(String userId, Long projectId, Integer deadline) {
        // 先删除，后插入
        projectRateMapper.deleteByUserIdProjectId(userId, projectId);

        ProjectRateConfig projectRateConfig = speedLoanRateConfigService.getRateConfigByDeadline(deadline);
        if (projectRateConfig == null) {
            log.error("极速借设置标的(担保服务费、平台管理费)每期费率占比出错：未找到费率配置，userId={}, projectId={}, deadline={}", userId, projectId, deadline);
            throw new BizException("TRD4000001");
        }

        List<RateConfigPercent> rateConfigPercentList = rateConfigPercentMapper.queryConfigPercentByRateConfigId(projectRateConfig.getId());
        if (rateConfigPercentList.size() == 0) {
            log.error("极速借设置标的(担保服务费、平台管理费)每期费率占比出错：未找到占比配置，userId={}, projectId={}, deadline={}", userId, projectId, deadline);
            throw new BizException("TRD4000002");
        }

        List<ProjectRate> projectRateList = new ArrayList<>();
        BigDecimal guaranteeServiceFeeTotalPercent = BigDecimal.ZERO;
        BigDecimal platformManageFeeTotalPercent = BigDecimal.ZERO;

        for (int i = 1; i <= deadline; i++) {
            RateConfigPercent rateConfigPercent = rateConfigPercentList.get(i - 1);
            if (rateConfigPercent.getCurrentPeriod() == null || rateConfigPercent.getCurrentPeriod() != i) {
                log.error("极速借设置标的(担保服务费、平台管理费)每期费率占比出错：当期占比配置错误，currentPeriod={}, userId={}, projectId={}, deadline={}", i, userId, projectId, deadline);
                throw new BizException("TRD4000003");
            }

            guaranteeServiceFeeTotalPercent = guaranteeServiceFeeTotalPercent.add(rateConfigPercent.getGuaranteeServiceFeePercent());
            platformManageFeeTotalPercent = platformManageFeeTotalPercent.add(rateConfigPercent.getPlatformManageFeePercent());

            ProjectRate projectRate = new ProjectRate();

            projectRate.setId(snowflakeIdWorker.nextId());
            projectRate.setProjectId(projectId);
            projectRate.setBorrowUserId(userId);
            projectRate.setCurrentPeriod(rateConfigPercent.getCurrentPeriod());
            projectRate.setGuaranteeServiceFeePercent(rateConfigPercent.getGuaranteeServiceFeePercent()); // 担保服务费百分比
            projectRate.setPlatformManageFeePercent(rateConfigPercent.getPlatformManageFeePercent()); // 平台管理费百分比
            projectRate.setAfterSeekAdviceServiceFeeRate(BigDecimal.ZERO); // 后置咨询服务费率
            projectRate.setCreateTime(new Date());

            projectRateList.add(projectRate);
        }

        if (guaranteeServiceFeeTotalPercent.compareTo(BigDecimal.ONE) != 0) {
            log.error("极速借设置标的(担保服务费、平台管理费)每期费率占比出错：担保服务费总占比错误，userId={}, projectId={}, deadline={}", userId, projectId, deadline);
            throw new BizException("TRD4000004");
        }

        if (platformManageFeeTotalPercent.compareTo(BigDecimal.ONE) != 0) {
            log.error("极速借设置标的(担保服务费、平台管理费)每期费率占比出错：平台管理费总占比错误，userId={}, projectId={}, deadline={}", userId, projectId, deadline);
            throw new BizException("TRD4000005");
        }

        projectRateList.forEach(projectRate -> {
            projectRateMapper.insertSelective(projectRate);
        });
    }

    /**
     * 卡牛借款费率
     * @param userId
     * @param projectId
     * @param deadline
     */
    public void cardniuProjectRateCreat(String userId,Long projectId,Integer deadline){
        //先删除，后插入
        projectRateMapper.deleteByUserIdProjectId(userId,projectId);
        ProjectRateConfig projectRateConfig = speedLoanRateConfigService.getCardcardniuRateConfigByDeadline(deadline);
        List<RateConfigPercent> rateConfigPercentList = rateConfigPercentMapper.queryConfigPercentByRateConfigId(projectRateConfig.getId());
        for(RateConfigPercent rateConfigPercent:rateConfigPercentList){
            ProjectRate projectRate = new ProjectRate();
            BeanUtils.copyProperties(rateConfigPercent,projectRate);
            projectRate.setId(snowflakeIdWorker.nextId());
            projectRate.setBorrowUserId(userId);
            projectRate.setProjectId(projectId);
            projectRate.setCreateTime(new Date());
            projectRateMapper.insertSelective(projectRate);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void addOrUpdateCallRiskRuleRecord(Long projectId) {
        //3.插入待天称风险规则记录;
        CallRiskRuleRecord callRiskRuleRecord2Select=callRiskRuleRecordMapper.selectByPrimaryKeyForUpdate(projectId);
        Date now=new Date();
        //若存在已经过借款反欺诈且风险规则已回调的记录,则表示是由于退回再次发起的借款;
        if(callRiskRuleRecord2Select!=null
                &&callRiskRuleRecord2Select.getLoanFakeStatus().equals((byte)1)){
            CallRiskRuleRecord callRiskRuleRecord2Update = new CallRiskRuleRecord();
            callRiskRuleRecord2Update.setProjectId(projectId);
            callRiskRuleRecord2Update.setLoanFakeStatus((byte) 0);
            callRiskRuleRecord2Update.setRiskRuleCallBackStatus((byte)0);
            callRiskRuleRecord2Update.setCallTimes((byte) 0);
            callRiskRuleRecord2Update.setUpdateTime(now);

            callRiskRuleRecordMapper.updateByPrimaryKeySelective(callRiskRuleRecord2Update);
        }else {
            CallRiskRuleRecord callRiskRuleRecord = new CallRiskRuleRecord();
            callRiskRuleRecord.setCreateTime(now);
            callRiskRuleRecord.setProjectId(projectId);
            callRiskRuleRecord.setLoanFakeStatus((byte) 0);
            callRiskRuleRecord.setRiskRuleCallBackStatus((byte) 0);
            callRiskRuleRecord.setCallTimes((byte) 0);

            callRiskRuleRecordMapper.insertSelective(callRiskRuleRecord);
        }
    }

    /**
     * 通讯录回流成功处理
     * @author xueyuke
     */
    @Transactional(rollbackFor = Exception.class)
    public void addressListBackflowSuccess(AddressListWaitBackflowRecord addressListWaitBackflowRecord){
        //1.锁标的;
        projectMapper.selectByPrimaryKeyForUpdate(addressListWaitBackflowRecord.getProjectId());

        //2.修改标的通讯录回流状态为已回流;
        Project project2Update=new Project();
        project2Update.setProjectId(addressListWaitBackflowRecord.getProjectId());
        project2Update.setContactsBackflowStatus(ContactsBackflowStatusEnum.SUCCESS.getValue());
        project2Update.setUpdateTime(new Date());

        projectCommonService.updateByPrimaryKeySelective(project2Update);

        //3.物理删除通讯录待回流记录;
        addressListWaitBackflowRecordMapper.deleteByPrimaryKey(addressListWaitBackflowRecord.getProjectId());

        //4.在正常发布标的时新增/退回重新提交标的时修改 风险规则待调用记录;
        ((SpeedLoanService)AopContext.currentProxy()).addOrUpdateCallRiskRuleRecord(addressListWaitBackflowRecord.getProjectId());
    }

    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void deleteAddressListBackflowByProjectId(Long projectId){
        //3.物理删除通讯录待回流记录;
        addressListWaitBackflowRecordMapper.deleteByPrimaryKey(projectId);
    }

    public void backProjectBasicInfoCheck(SpeedLoanApplyForBackRequestDTO requestDTO, SpeedLoanApplyCommonResponseDTO responseDTO) {
        Project project = projectMapper.selectByPrimaryKey(requestDTO.getProjectId());
        if (project == null) {
            this.speedLoanPublishCheck_excetipnResponseDeal(LoanLimitMessageEnum.LIMIT_10045,responseDTO);
        }
        byte status = project.getStatus();
        Integer subStatus = project.getSubStatus();
        if (ProjectSubStatusEnum.CHECKING_BACK.getParentStatusEnum().getStatus().byteValue() != status ||
                (ProjectSubStatusEnum.CHECKING_BACK.getSubStatus() != subStatus
                        &&ProjectSubStatusEnum.CHECKING_BACK_PHONEOPERATOR_TIMEOUT.getSubStatus() != subStatus
                        &&ProjectSubStatusEnum.CHECKING_BACK_ADDRESSLIST_TIMEOUT.getSubStatus() != subStatus)) {
            this.speedLoanPublishCheck_excetipnResponseDeal(LoanLimitMessageEnum.LIMIT_10046,responseDTO);
        }
    }

    /**
     * 退回标的信息查询
     * @param userId
     * @return
     */
    public SpeedLoanQueryResponseDTO speedLoanQueryForBack(String userId){
        Project project = projectMapper.speedLoanQueryForBack(userId);
        log.info("speedLoanQueryForBack userId={},project={}",userId,JSON.toJSONString(project));
        if(project==null){
            return null;
        }
        SpeedLoanQueryResponseDTO speedLoanQueryResponseDTO = new SpeedLoanQueryResponseDTO();
        BeanUtils.copyProperties(project,speedLoanQueryResponseDTO);

        //获取回退原因
        speedLoanQueryResponseDTO.setDetailBack(this.getDetailBack(userId,project.getProjectId(),project.getSubStatus()));
        return speedLoanQueryResponseDTO;
    }

    //获取回退原因
    private SpeedLoanQueryResponseDTO.DetailBack getDetailBack(String userId,Long projectId,Integer subStatus){
        SpeedLoanQueryResponseDTO.DetailBack detailBack = new SpeedLoanQueryResponseDTO.DetailBack();

        try {
            //如果是人工审核回退
            if(ProjectSubStatusEnum.CHECKING_BACK.getSubStatus()==subStatus){
                ProjectAuditDecision projectAuditDecision = projectAuditDecisionMapper.selectForBackProject(userId, projectId);
                log.info("speedLoanQueryForBack userId={},projectAuditDecision={}",userId,JSON.toJSONString(projectAuditDecision));
                Optional.ofNullable(projectAuditDecision).ifPresent(d->{
                    detailBack.setReasonList(this.getBackReasonList(d.getAuditReason()));
                    detailBack.setProcessScheme(d.getProcessScheme());
                });
            }else{//如果是自动审核回退
                detailBack.setReasonList(Arrays.asList(ProjectSubStatusEnum.enumOf(subStatus).getDesc()));
                Optional.ofNullable(
                        ProjectSubStatusEnum.CHECKING_BACK_PHONEOPERATOR_TIMEOUT.getSubStatus()==subStatus?ProcessSchemeEnum.UPDATE_CREDIT_INFO:ProcessSchemeEnum.UPDATE_LOAN_INFO
                ).ifPresent(processSchemeEnum->{
                    detailBack.setProcessScheme(processSchemeEnum.getValue());
                });
            }
        } catch (Exception e) {
            log.error("getDetailBack error",e);
        }
        return detailBack;
    }

    private List<String> getBackReasonList(String auditReason){
        return Optional.ofNullable(auditReason).map(reason->{
            String[] auditReasonArray = auditReason.split("\\|");
            return projectAuditConfigMapperExt.selectAuditReasonNameByReasonCodeList(Arrays.asList(auditReasonArray));
        }).orElse(null);
    }

    /**
     * 新增审核要点结果记录
     * @param projectId
     * @param userId
     * @param auditResult
     * @param auditPoints
     */
    public void addAutoAuditResult(Long projectId,String userId,Byte auditResult,String auditPoints){
        //1.新增审核或更新审核要点记录;
    	// shardingjdbc 强制走主库
		if (!HintManagerHolder.isMasterRouteOnly()) {
            HintManagerHolder.clear();
            HintManager hintManager = HintManager.getInstance();
            hintManager.setMasterRouteOnly();
        }
        AutoAuditModelResult autoAuditModelResult4Select=autoAuditModelResultMapper.selectLastOneByProjectIdAndUserId(userId,projectId);
        if(autoAuditModelResult4Select==null){
            AutoAuditModelResult autoAuditModelResult=new AutoAuditModelResult();
            autoAuditModelResult.setId(snowflakeIdWorker.nextId());
            autoAuditModelResult.setProjectId(projectId);
            autoAuditModelResult.setUserId(userId);
            autoAuditModelResult.setAuditPoints(auditPoints);
            autoAuditModelResult.setAuditResult(auditResult);
            autoAuditModelResult.setCreateTime(new Date());

            autoAuditModelResultMapper.insertSelective(autoAuditModelResult);
        }else{
            AutoAuditModelResult autoAuditModelResult2Update=new AutoAuditModelResult();
            autoAuditModelResult2Update.setId(autoAuditModelResult4Select.getId());
            autoAuditModelResult2Update.setAuditPoints(auditPoints);
            autoAuditModelResult2Update.setAuditResult(auditResult);
            autoAuditModelResult2Update.setUpdateTime(new Date());

            autoAuditModelResultMapper.updateByPrimaryKeySelective(autoAuditModelResult2Update);
        }

        //2.新增审核要点结果历史记录;
        AutoAuditModelResultRecord autoAuditModelResultRecord=new AutoAuditModelResultRecord();
        autoAuditModelResultRecord.setId(snowflakeIdWorker.nextId());
        autoAuditModelResultRecord.setProjectId(projectId);
        autoAuditModelResultRecord.setUserId(userId);
        autoAuditModelResultRecord.setAuditPoints(auditPoints);
        autoAuditModelResultRecord.setAuditResult(auditResult);
        autoAuditModelResultRecord.setCreateTime(new Date());
        autoAuditModelResultRecord.setUpdateTime(new Date());

        autoAuditModelResultRecordMapper.insertSelective(autoAuditModelResultRecord);
    }

    /**
     * 更新标的自动审核结果
     * @param projectId
     * @param autoAuditResult
     */
    public void updateAutoAuditResult4Project(Long projectId,Byte autoAuditResult){
        Project project=new Project();
        project.setProjectId(projectId);
        project.setAutoAuditResult(autoAuditResult);

        projectMapper.updateByPrimaryKeySelective(project);
    }

    /**
     * 上标补偿
     * @param projectPushRecord
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public void initProejctPushRecord(ProjectPushRecord projectPushRecord){
        log.info("初始化标的推送任务,标的ID={}",projectPushRecord.getProjectNo());
        Project project=projectMapper.selectByPrimaryKey(Long.valueOf(projectPushRecord.getProjectNo()));
        log.info("初始化标的推送任务,标的ID={},标的信息={}",projectPushRecord.getProjectNo(),JSON.toJSONString(project));
        if(project==null){
            throw new BizException("TRD20001");
        }

        projectPushRecordMapper.insertSelective(projectPushRecord);
        log.info("初始化标的推送任务,标的ID={},任务初始化完成.",projectPushRecord.getProjectNo());
    }

    public com.niiwoo.tripod.lanmao.enums.RepaymentTypeEnum transRepaymentType2LM(RepaymentTypeEnum repaymentTypeEnum){
        switch (repaymentTypeEnum){
            case REPAY_PRINCIPAL_INTEREST_AT_TERM:
                return com.niiwoo.tripod.lanmao.enums.RepaymentTypeEnum.ONE_TIME_SERVICING;
            case AVERAGE_CAPITAL_PLUS_INTEREST:
                return com.niiwoo.tripod.lanmao.enums.RepaymentTypeEnum.FIXED_PAYMENT_MORTGAGE;
            case MONTHLY_INTEREST_PAYMENT_DUE:
                return com.niiwoo.tripod.lanmao.enums.RepaymentTypeEnum.FIRSEINTREST_LASTPRICIPAL;
            default :
                throw new BizException("TRD20004");
        }
    }

    /**
     * 新增人工审核任务
     * @param project
     */
    public void addAuditWorkTask(Project project) {
        //1.转神盾系统人工审核;
        AddAuditWorkTaskReqDTO addAuditWorkTaskReqDTO=new AddAuditWorkTaskReqDTO();
        addAuditWorkTaskReqDTO.setProjectId(project.getProjectId());
        addAuditWorkTaskReqDTO.setBorrowerUserId(project.getBorrowUserId());
        addAuditWorkTaskReqDTO.setBorrowerUserName(project.getBorrowUserName());
        addAuditWorkTaskReqDTO.setBorrowerMobile(project.getBorrowMobile());
        addAuditWorkTaskReqDTO.setChannelCode(project.getFromSource());
        addAuditWorkTaskReqDTO.setApplyTime(project.getSubmitTime());

        log.info("天称审核要点反欺诈回调,标的ID={},开始调用神盾人工审核任务MQ,请求参数={}",project.getProjectId(),JSON.toJSONString(addAuditWorkTaskReqDTO));
        rabbitTemplate.convertAndSend(RabbitConstant.Exchange.AUDIT_WORK_TASK_ADD,RabbitConstant.RoutingKey.AUDIT_WORK_TASK_ADD ,
                JSON.toJSONString(addAuditWorkTaskReqDTO));
        log.info("天称审核要点反欺诈回调,标的ID={},结束调用神盾人工审核任务MQ,请求参数={}",project.getProjectId(),JSON.toJSONString(addAuditWorkTaskReqDTO));
    }

    /**
     * 查询可推送标的列表
     * @return
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public List<ProjectPushRecord> selectPushProjectList(){
        return projectPushRecordMapper.selectPushProjectList();
    }

    /**
     * 查询标的上标成功记录
     * @return
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public ProjectPushRecord selectPushProjectSuccessRecordByProjectId(Long projectId){
        return projectPushRecordMapper.selectPushProjectSuccessRecordByProjectId(projectId);
    }

    //借款红包占用记录生成
    public ProjectBorrowerPrizeOccupyRecord buildProjectBorrowerPrizeOccupyRecord(BorrowPrizeOccupyDTO borrowPrizeOccupyDTO, Long projectId){
        ProjectBorrowerPrizeOccupyRecord projectBorrowerPrizeOccupyRecord = new ProjectBorrowerPrizeOccupyRecord();
        projectBorrowerPrizeOccupyRecord.setOrderNo(snowflakeIdWorker.nextId());
        projectBorrowerPrizeOccupyRecord.setPrizeId(borrowPrizeOccupyDTO.getPrizeId());
        try {
            Date now = new Date();
            projectBorrowerPrizeOccupyRecord.setId(snowflakeIdWorker.nextId());
            projectBorrowerPrizeOccupyRecord.setProjectType(UserPrizeSuitProjectTypeEnum.SPEED.getType().byteValue());
            projectBorrowerPrizeOccupyRecord.setPrizeType(borrowPrizeOccupyDTO.getPrizeType());
            projectBorrowerPrizeOccupyRecord.setDeadline(borrowPrizeOccupyDTO.getDeadline());
            projectBorrowerPrizeOccupyRecord.setBorrowerUserId(borrowPrizeOccupyDTO.getUserId());
            projectBorrowerPrizeOccupyRecord.setProjectId(projectId);
            projectBorrowerPrizeOccupyRecord.setAmount(borrowPrizeOccupyDTO.getLoanAmount());
            projectBorrowerPrizeOccupyRecord.setOccupyStatus(BorrowPrizeOccupyEnum.OccupyStatusEnum.INIT.getStatus());
            projectBorrowerPrizeOccupyRecord.setCreateTime(now);
            projectBorrowerPrizeOccupyRecord.setUpdateTime(now);
            projectBorrowerPrizeOccupyRecordMapper.insert(projectBorrowerPrizeOccupyRecord);
        } catch (Exception e) {
            log.error("insertProjectBorrowerPrizeOccupyRecord error borrowPrizeOccupyDTO="+JSON.toJSONString(borrowPrizeOccupyDTO),e);
        }
        return projectBorrowerPrizeOccupyRecord;
    }

    public void updateProjectBorrowerPrizeOccupyRecordStatus(ProjectBorrowerPrizeOccupyRecord projectBorrowerPrizeOccupyRecord,BorrowPrizeOccupyEnum.OccupyStatusEnum occupyStatusEnum){
        String logHead = "updateProjectBorrowerPrizeOccupyRecordStatus start,projectBorrowerPrizeOccupyRecord="+JSON.toJSONString(projectBorrowerPrizeOccupyRecord)+",occupyStatusEnum="+JSON.toJSONString(occupyStatusEnum)+" ";
        log.info(logHead+"start");
        try {
            ProjectBorrowerPrizeOccupyRecord record = new ProjectBorrowerPrizeOccupyRecord();
            record.setId(projectBorrowerPrizeOccupyRecord.getId());
            record.setBorrowerUserId(projectBorrowerPrizeOccupyRecord.getBorrowerUserId());
            record.setProjectId(projectBorrowerPrizeOccupyRecord.getProjectId());
            record.setOccupyStatus(occupyStatusEnum.getStatus());
            record.setUpdateTime(new Date());
            projectBorrowerPrizeOccupyRecordMapper.updateOccupyStatus(record);
        } catch (Exception e) {
            log.error(logHead,e);
        }
    }

    /**
     * 是否初次借款,仅限于天称;0:初次借款; 1:再次借款.request_type字段为1(极速借)时,并且此字段为1时,表示极速借二次借款。
     * @return
     */
    public Integer isFirstTime4TianCheng(String userId){
        return projectMapper.selectAuditPassProjectCount(userId)==null?0:1;
    }

    /**
     * 查询风险规则调用超时的标的列表
     * @return
     */
    public List<CallRiskRuleRecord> searchTimeOutRecordList(){
        return callRiskRuleRecordMapper.selectTimeOutRecordList();
    }

    /**
     * 查询待调用天称风险规则记录
     * @return
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public List<CallRiskRuleRecord> searchWaitRiskRuleRecordList(){
        return callRiskRuleRecordMapper.selectWaitRiskRuleRecordList();
    }

    /**
     * 清理风险规则记录
     */
    public int cleanCallRiskRuleRecord(){
        return callRiskRuleRecordMapper.cleanCallRiskRuleRecord();
    }

    /**
     * 更新风险规则调用记录
     * @param callRiskRuleRecord
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateCallRiskRuleRecord(CallRiskRuleRecord callRiskRuleRecord){
        callRiskRuleRecordMapper.updateByPrimaryKeySelective(callRiskRuleRecord);
    }

    /**
     * 更新风险规则调用记录发起反欺诈诈状态
     * @param projectId
     * @param loanFakeStatus
     */
    public void updateCallRiskRuleRecordLoanFakeStatus(Long projectId,Byte loanFakeStatus){
        CallRiskRuleRecord callRiskRuleRecord2Update=new CallRiskRuleRecord();
        callRiskRuleRecord2Update.setProjectId(projectId);
        callRiskRuleRecord2Update.setLoanFakeStatus(loanFakeStatus);

        callRiskRuleRecordMapper.updateByPrimaryKeySelective(callRiskRuleRecord2Update);
    }

    /**
     * 删除风险规则调用记录
     * @param projectId
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteCallRiskRuleRecord(Long projectId){
        callRiskRuleRecordMapper.deleteByPrimaryKey(projectId);
    }

    /**
     * 查询通录讯待回流列表
     * @return
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public List<AddressListWaitBackflowRecord> searchAddressListWaitBackflowRecordList(){
        return addressListWaitBackflowRecordMapper.selectAddressListWaitBackflowRecordList();
    }

    /**
     * 查询通录讯回流超时退回列表
     * @return
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public List<AddressListWaitBackflowRecord> searchAddressListTimeoutRecordList(){
        return addressListWaitBackflowRecordMapper.selectAddressListTimeoutRecordList();
    }

    /**
     * 是融360标?
     * @param fromSource
     * @return
     */
    public boolean isR360(Byte fromSource){
        return fromSource.equals(ProjectFromSourceEnum.R360.getType());
    }

    /**
     * 超时退回标的
     */
    @Transactional(isolation = Isolation.READ_COMMITTED,rollbackFor = Exception.class)
    public void returnProject(Long projectId, ProjectSubStatusEnum projectSubStatusEnum){
        Project project=projectMapper.selectByPrimaryKeyForUpdate(projectId);
        if (project == null) {
            log.error("退回标的,标的ID={},标的不存在.",projectId);
            return;
        }

        if(isR360(project.getFromSource())){
            log.error("退回标的,标的ID={},融360标的不进行自动退回操作.",projectId);
            return;
        }

        if(!ProjectStatusEnum.CHECKING.getStatus().equals(project.getStatus())){
            log.error("退回标的,标的ID={},标的状态不是筹款中.",projectId);
            return;
        }

        //1.更新标的子状态为退回;
        Project project2Update=new Project();
        project2Update.setProjectId(project.getProjectId());
        project2Update.setSubStatus(projectSubStatusEnum.getSubStatus());
        if(ProjectSubStatusEnum.CHECKING_BACK_ADDRESSLIST_TIMEOUT.equals(projectSubStatusEnum)) {
            project2Update.setContactsBackflowStatus(ContactsBackflowStatusEnum.FAIL.getValue());
        }
        project2Update.setUpdateTime(new Date());

        projectMapper.updateByPrimaryKeySelective(project2Update);

        //2.异步退回红包;
        if(project.getPrizeId() != null && project.getPrizeId() > 0){
            ProjectBackoutBorrowPrize backPrize = new ProjectBackoutBorrowPrize();
            backPrize.setProjectId(project.getProjectId());
            backPrize.setUserId(project.getBorrowUserId());
            backPrize.setPrizeId(project.getPrizeId());
            backPrize.setCreateTime(new Date());

            projectBackoutBorrowPrizeMapperExt.insertSelective(backPrize);
        }
    }


    /**
     * 遍历期数集合(Jaylin)
     * @return
     */
    public Set<Integer> listDeadlines() {
        Set<Integer> deadlineSet = new HashSet<>();
        List<ProjectLoanDeadlineConfig> projectLoanDeadlineConfigs = projectLoanDeadlineConfigMapper.selectAll(null);
        for (ProjectLoanDeadlineConfig projectLoanDeadlineConfig : projectLoanDeadlineConfigs) {
            String deadlineStr = projectLoanDeadlineConfig.getDeadline();
            List<Integer> deadlines = this.getDealLineList(deadlineStr);
            for (Integer deadline : deadlines) {
                deadlineSet.add(deadline);
            }
        }

        return deadlineSet;
    }

    /**
     * 推标至存管成功
     * @param project
     */
    @Transactional(isolation = Isolation.READ_COMMITTED,rollbackFor = Exception.class)
    public void pushProjectSuccess(Project project,ProjectInvesting projectInvesting,PushProjectRequestDTO pushProjectRequestDTO,Map<String,Date> projectDateTime) {
        Project projectForUpdate=projectMapper.selectByPrimaryKeyForUpdate(project.getProjectId());
        if(projectForUpdate==null){
            log.error("推标,标的ID={},发生异常,原因是获取标的锁时标的不存在.", project.getProjectId());
            throw new BizException("TRD20001");
        }

        if(projectForUpdate.getStatus()==null||!projectForUpdate.getStatus().equals(ProjectStatusEnum.CHECKING.getStatus())){
            log.error("推标,标的ID={},发生异常,原因是标的状态不在审核中.", project.getProjectId());
            throw new BizException("TRD_700001");
        }

        //1.更新标的状态;
        Project project2Update = new Project();
        project2Update.setProjectId(project.getProjectId());
        project2Update.setStatus(ProjectStatusEnum.COLLECTING.getStatus().byteValue());
        project2Update.setSubStatus(ProjectSubStatusEnum.COLLECTING_INIT.getSubStatus());
        if (projectForUpdate.getAuditedTime() == null) {
            if (pushProjectRequestDTO.getAuditedTime() == null) {
                pushProjectRequestDTO.setAuditedTime(new Date());
            }
            project2Update.setAuditedTime(pushProjectRequestDTO.getAuditedTime());
        }
        project2Update.setAuditManagerId(pushProjectRequestDTO.getAuditManagerId());
        project2Update.setAuditManagerName(pushProjectRequestDTO.getAuditManagerName());
        project2Update.setManualAuditResult(ManualAuditResultEnum.PASS.getValue());

        Date now = projectDateTime.get("startDateTime");
        Date endDate = projectDateTime.get("endDateTime");
        project2Update.setPublishTime(now);
//        project2Update.setInvestEndTime(endDate);
        project2Update.setUpdateTime(now);
        project2Update.setIsPublish(ProjectIsPublishEnum.YES.getValue());

        // 运营投资加息活动(V5.4.5 增加ChanelCode判断，只有APP端才需要加息)
        /**
         * v5.4.5之前分端发标的逻辑  从app-非app端，不加息，非-app到app，要加息  以前的是临时方案
         * v5.5.0跟产品确认t_tc_invest_add_interest_rate_config所有加息或者不加息从配置表取值，
         * 添加了channel——code字段，所有加息，需要通过 期限+利率+orgID+channel_code 一起查，配置表有加息，则加息，不一定只有app
         */
        //if (ChannelCodeEnum.APP.getChanelCode().equals(project.getChannelCode())) {
        this.projectRaiseRateHandle(project, project2Update);
        //}


        projectCommonService.updateByPrimaryKeySelective(project2Update);

        // 设置标的担保公司、逾期垫付天数
        projectLocalService.setProjectGuaranteeCompany(project);

        //2.将标的放入可投标的列表中;
        projectInvesting.setActivityId(project2Update.getActivityId());
        projectInvesting.setActivityRaiseRate(project2Update.getActivityRaiseRate());

        investService.addProjectInvesting(projectInvesting);

        //3.记录标的动态;
        ProjectDynamicDTO projectDynamicDTO=new ProjectDynamicDTO();
        projectDynamicDTO.setUserId(project.getBorrowUserId());
        projectDynamicDTO.setProjectId(project.getProjectId());
        projectDynamicDTO.setProjectDynamicEnum(ProjectDynamicEnum.AUDIT_SUCCESS);
        projectDynamicDTO.setTradeTypeEnum(ProjectDynamicDTO.TradeTypeEnum.REPAYMENT);
        projectLocalService.addProjectDynamicRecord(projectDynamicDTO);

        //4.若是通过通偿机制上标的，则需要更新补偿记录表状态为成功，以结束该补偿任务;
        if(pushProjectRequestDTO.getProjectPushRecordId()!=null) {
            ((SpeedLoanService)AopContext.currentProxy()).deletePushProjectRecordById(pushProjectRequestDTO.getProjectPushRecordId());
        }

        //5.人工审核需要更新最终审核结果字段
        if(pushProjectRequestDTO.getPushFromEnum().equals(PushProjectRequestDTO.PushFromEnum.HAND_AUDIT)){
            ((SpeedLoanService)AopContext.currentProxy()).updateFinalAuditResult(project.getProjectId(),FinalAuditResultEnum.PASS);
        }

        // 若标的分到智能投，则需要发送MQ通知智能投业务处理;
        if (projectLocalService.isZhiNengTou(project.getChannelCode())) {
            rabbitTemplate.convertAndSend(MqConstant.PROJECT_PACKAGE_ADD_PROJECT_EXCHANGE, MqConstant.PROJECT_PACKAGE_ADD_PROJECT_ROUTING, project.getProjectId());
            log.info("推标,标的ID={},已推送消息至智能投.", project.getProjectId());
        }

        try {
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
                @Override
                public void afterCommit() {
                    //6.推送自动投资MQ
                    log.info("推标,标的ID={},发送自动投资MQ开始", project.getProjectId());
                    rabbitTemplate.convertAndSend(RabbitConstant.Exchange.AUTO_INVEST_PROJECT, RabbitConstant.RoutingKey.AUTO_INVEST_PROJECT, project.getProjectId());
                    log.info("推标,标的ID={},发送自动投资MQ结束", project.getProjectId());

                    //7.推送标的快照MQ
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("projectId", project.getProjectId());
                    jsonObject.put("borrowerUserId", project.getBorrowUserId());
                    jsonObject.put("productType", project.getType());
                    log.info("推标,标的ID={},发送标的快照MQ开始,请求参数={}", project.getProjectId(), JSON.toJSONString(jsonObject));
                    rabbitTemplate.convertAndSend(MqConstant.CREATE_PROJECT_SNAPSHOT_EXCHANGE, MqConstant.CREATE_PROJECT_SNAPSHOT_ROUTE, JSON.toJSONString(jsonObject));
                    log.info("推标,标的ID={},发送标的快照MQ结束", project.getProjectId());

                    //8.天称标的状态变更回流事件
                    ProjectStatusChangeBackFlowRequestDTO projectStatusChangeBackFlowRequestDTO = new ProjectStatusChangeBackFlowRequestDTO();
                    projectStatusChangeBackFlowRequestDTO.setStatus(String.valueOf(ProjectSubStatusEnum.COLLECTING_INIT.getSubStatus()));
                    projectStatusChangeBackFlowRequestDTO.setFromStatus(String.valueOf(ProjectSubStatusEnum.CHECKING_INIT.getSubStatus()));
                    projectStatusChangeBackFlowRequestDTO.setProjectId(project.getProjectId());

                    log.info("推标,标的ID={},发送天称标的状态变更回流事件开始,请求参数={}", project.getProjectId(), JSON.toJSONString(projectStatusChangeBackFlowRequestDTO));
                    tianChengDataBackFlowLocalService.projecctStatusChange(projectStatusChangeBackFlowRequestDTO);
                    log.info("推标,标的ID={},发送天称标的状态变更回流事件结束", project.getProjectId());
                }
            });
        }catch(Exception e){
            log.error("推标,标的ID={},推标成功事务提交后发送业务消息时发生系统异常,原因={}", project.getProjectId(),e);
        }

    }


    /**
     * 卡牛-推标至存管成功
     *
     * @param project
     */
    @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
    public void cardNiuPushProjectSuccess(Project project, ProjectInvesting projectInvesting, PushProjectRequestDTO pushProjectRequestDTO) {
        Project projectForUpdate = projectMapper.selectByPrimaryKeyForUpdate(project.getProjectId());
        if (projectForUpdate == null) {
            log.error("卡牛-推标,标的ID={},发生异常,原因是获取标的锁时标的不存在.", project.getProjectId());
            throw new BizException("TRD20001");
        }

        if (projectForUpdate.getStatus() == null || !projectForUpdate.getStatus().equals(ProjectStatusEnum.CHECKING.getStatus())) {
            log.error("卡牛-推标,标的ID={},发生异常,原因是标的状态不在审核中.", project.getProjectId());
            throw new BizException("TRD_700001");
        }

        //1.更新标的状态;
        Project project2Update = new Project();
        project2Update.setProjectId(project.getProjectId());
        project2Update.setStatus(ProjectStatusEnum.COLLECTING.getStatus().byteValue());
        project2Update.setSubStatus(ProjectSubStatusEnum.COLLECTING_INIT.getSubStatus());
        if (projectForUpdate.getAuditedTime() == null) {
            if (pushProjectRequestDTO.getAuditedTime() == null) {
                pushProjectRequestDTO.setAuditedTime(new Date());
            }
            project2Update.setAuditedTime(pushProjectRequestDTO.getAuditedTime());
        }
        project2Update.setAuditManagerId(pushProjectRequestDTO.getAuditManagerId());
        project2Update.setAuditManagerName(pushProjectRequestDTO.getAuditManagerName());
        project2Update.setManualAuditResult(ManualAuditResultEnum.PASS.getValue());
        //        project2Update.setChannelCode(getChannelCode(project));
        //
        //         判断是否存在分时放标的配置
        //        Date releaseTime = loanLocalService.getProjectReleaseTimeByConfig();
        //        if (releaseTime == null) {
        //             修改标的是否放标状态。标的是否已释放 0:未释放1:已经释放
        //            project2Update(1);
        //        } else {
        //             设置标的释放时间,由计划任务进行后续处理
        //            project2Update.setReleaseTime(releaseTime);
        //        }
        Date now = new Date();
        project2Update.setPublishTime(now);

        //boolean isCardLoan = project.getType().equals(com.niiwoo.civet.trade.enums.ProjectTypeEnum.CARD_NIU_LOAN.getValue());
        //boolean isFormCardNiu = project.getFromSource().equals(ProjectFromSourceEnum.CARD_NIU.getType());
        String investDeadline = tradeConfigService.selectTradeConfigByEmun(TradeConfigEnum.CARDNIU_INVESTDEADLINE);

        if (StringUtils.isEmpty(investDeadline)) {
            log.info("卡牛-推标,标的ID={},筹款期限未配置.", project.getProjectId());
            throw new RuntimeException("筹款期限未配置.");
        }
        project2Update.setInvestEndTime(org.apache.commons.lang3.time.DateUtils.addDays(now, Integer.valueOf(investDeadline)));
        project2Update.setUpdateTime(now);
        projectCommonService.updateByPrimaryKeySelective(project2Update);

        //2.将标的放入可投标的列表中;
        investService.addProjectInvesting(projectInvesting);

        //3.记录标的动态;
        ProjectDynamicDTO projectDynamicDTO = new ProjectDynamicDTO();
        projectDynamicDTO.setUserId(project.getBorrowUserId());
        projectDynamicDTO.setProjectId(project.getProjectId());
        projectDynamicDTO.setProjectDynamicEnum(ProjectDynamicEnum.AUDIT_SUCCESS);
        projectDynamicDTO.setTradeTypeEnum(ProjectDynamicDTO.TradeTypeEnum.REPAYMENT);
        projectLocalService.addProjectDynamicRecord(projectDynamicDTO);

        //4.若是通过通偿机制上标的，则需要更新补偿记录表状态为成功，以结束该补偿任务;
        if (pushProjectRequestDTO.getProjectPushRecordId() != null) {
            ((SpeedLoanService) AopContext.currentProxy()).deletePushProjectRecordById(pushProjectRequestDTO.getProjectPushRecordId());
        }

        //5.人工审核需要更新最终审核结果字段
        if (pushProjectRequestDTO.getPushFromEnum().equals(PushProjectRequestDTO.PushFromEnum.HAND_AUDIT)) {
            ((SpeedLoanService) AopContext.currentProxy()).updateFinalAuditResult(project.getProjectId(), FinalAuditResultEnum.PASS);
        }

        try {
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
                @Override
                public void afterCommit() {
                    //6.推送自动投资MQ
                    log.info("卡牛-推标,标的ID={},发送自动投资MQ开始", project.getProjectId());
                    rabbitTemplate.convertAndSend(RabbitConstant.Exchange.AUTO_INVEST_PROJECT, RabbitConstant.RoutingKey.AUTO_INVEST_PROJECT, project.getProjectId());
                    log.info("卡牛-推标,标的ID={},发送自动投资MQ结束", project.getProjectId());

                    //7.推送标的快照MQ
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("projectId", project.getProjectId());
                    jsonObject.put("borrowerUserId", project.getBorrowUserId());
                    jsonObject.put("productType", project.getType());
                    log.info("卡牛-推标,标的ID={},发送标的快照MQ开始,请求参数={}", project.getProjectId(), JSON.toJSONString(jsonObject));
                    rabbitTemplate.convertAndSend(MqConstant.CREATE_PROJECT_SNAPSHOT_EXCHANGE, MqConstant.CREATE_PROJECT_SNAPSHOT_ROUTE, JSON.toJSONString(jsonObject));
                    log.info("卡牛-推标,标的ID={},发送标的快照MQ结束", project.getProjectId());

                    //-- 调用MQ -- Exchange: LOAN_STATUS_EXCHANGE  Queue: LOAN_STATUS_QUEUE
                    //8.标的状态变更的都往这个MQ里面写入一下，方便资产端标的状态同步
                    LoanStatusDTO loanStatusDTO = new LoanStatusDTO();
                    loanStatusDTO.setProjectId(project2Update.getProjectId());
                    loanStatusDTO.setStatus(ProjectStatusEnum.COLLECTING.getStatus().byteValue());
                    loanStatusDTO.setSubStatus(ProjectSubStatusEnum.COLLECTING_INIT.getSubStatus());
                    loanStatusDTO.setType(project.getType());
                    rabbitTemplate.convertAndSend(CardNiuExternalMQConstants.Exchange.LOAN_STATUS_EXCHANGE,
                            CardNiuExternalMQConstants.getRoutingKey(CardNiuExternalMQConstants.Exchange.LOAN_STATUS_EXCHANGE, CardNiuExternalMQConstants.Queue.LOAN_STATUS_QUEUE), loanStatusDTO);
                    log.info("卡牛-推标，MQ发送标的信息：{}", loanStatusDTO);
                }
            });
        } catch (Exception e) {
            log.error("卡牛-推标,标的ID={},推标成功事务提交后发送业务消息时发生系统异常,原因={}", project.getProjectId(), e);
        }

    }
    
    /**
     * 确认订单上标
     * 
     * @param project
     * @param confirmSource
     */    
    @Transactional(rollbackFor = Exception.class)
	public void pushProjectConfirmLoan(Project project, byte confirmSource) {
    	try {
	    	// 当前时间
			Date now = new Date();    	
	
	        // 1.更新标的状态
			log.info("融360订单确认借款，更新标的状态，ProjectId:{}", project.getProjectId());
	        Project project2Update = new Project();
	        project2Update.setProjectId(project.getProjectId());
	        project2Update.setStatus(ProjectStatusEnum.COLLECTING.getStatus());
	        project2Update.setSubStatus(ProjectSubStatusEnum.COLLECTING_INIT.getSubStatus());
	        
	        project2Update.setPublishTime(now);
	        project2Update.setUpdateTime(now);
	        project2Update.setConfirmTime(now);
            // 用户确认之后维护最终审核状态
            project2Update.setFinalAuditResult(FinalAuditResultEnum.PASS.getResult());

			String investDeadline = tradeConfigService.selectTradeConfigByEmun(TradeConfigEnum.INVESTDEADLINE);
			project2Update.setInvestEndTime(org.apache.commons.lang3.time.DateUtils.addDays(now, Integer.valueOf(investDeadline)));

	        // 运营投资加息活动(V5.4.5 增加ChanelCode判断，只有APP端才需要加息)
			//if (ChannelCodeEnum.APP.getChanelCode().equals(project.getChannelCode())) {
				this.projectRaiseRateHandle(project, project2Update);
			//}

            projectCommonService.updateByPrimaryKeySelective(project2Update);

            // 设置标的担保公司、逾期垫付天数
            projectLocalService.setProjectGuaranteeCompany(project);

			// 2.将标的放入可投标的列表中
	        log.info("融360订单确认借款，生成可投资列表记录，ProjectId:{}", project.getProjectId());
			ProjectInvesting projectInvesting = bulidProjectInvesting(project);
			projectInvesting.setUpdateTime(now);
			projectInvesting.setCreateTime(now);
			projectInvesting.setPublishTime(now);
	        projectInvesting.setActivityId(project2Update.getActivityId());
	        projectInvesting.setActivityRaiseRate(project2Update.getActivityRaiseRate());
			
			investService.addProjectInvesting(projectInvesting);
	        
	        // 3.确认端是你我金融APP，需要发送MQ通知资产端
			if (ConfirmLoanSourceEnum.NIIWOO_CONFIRMED.getCode() == confirmSource) {
				R360OrderStatusChangedDTO r360OrderStatusChangedDTO = new R360OrderStatusChangedDTO();
				r360OrderStatusChangedDTO.setProjectId(project.getProjectId());
				r360OrderStatusChangedDTO.setR360OrderStatusEnumCode(R360OrderStatusEnum.CONFIRM_LOAN.getCode());
				r360OrderStatusChangedDTO.setR360OrderProjectSubStatusEnum(R360OrderProjectSubStatusEnum.COLLECTING_INIT);
				r360OrderStatusChangedDTO.setUpdateDate(now);
				log.info("融360订单确认借款，发关MQ信息通知资产端，ProjectId:{}，MQContent:{}", project.getProjectId(), JSONObject.toJSONString(r360OrderStatusChangedDTO));
				rabbitTemplate.convertAndSend(MqConstants.Exchange.ASSET_EXCHANGE, MqConstants.getRoutingKey(MqConstants.Exchange.ASSET_EXCHANGE, MqConstants.Queue.ORDER_STATUS_NOFIFY_FOR_COMMON),
						r360OrderStatusChangedDTO);
			}
	
	        // 4.推送自动投资MQ
			log.info("融360订单确认借款，推送自动投资队列，ProjectId:{}", project.getProjectId());
			rabbitTemplate.convertAndSend(RabbitConstant.Exchange.AUTO_INVEST_PROJECT, RabbitConstant.RoutingKey.AUTO_INVEST_PROJECT, project.getProjectId());
			
	        // 5.推送标的快照MQ
			log.info("融360订单确认借款，推送标的快照，ProjectId:{}", project.getProjectId());
	        JSONObject jsonObject = new JSONObject();
	        jsonObject.put("projectId", project.getProjectId());
	        jsonObject.put("borrowerUserId", project.getBorrowUserId());
	        rabbitTemplate.convertAndSend(MqConstant.CREATE_PROJECT_SNAPSHOT_EXCHANGE, MqConstant.CREATE_PROJECT_SNAPSHOT_ROUTE, JSON.toJSONString(jsonObject));
		} catch (Exception e) {
			log.error("融360确认借款，处理本地事务异常，异常原因：{}, ProjectId：{}", e.getMessage(), project.getProjectId());
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
		}
    }      
    
    /**
     * 构建可投资标的对象
     * 
     * @param project
     * 				项目内容
     * @return
     */
	private ProjectInvesting bulidProjectInvesting(Project project) {
		ProjectInvesting projectInvesting = new ProjectInvesting();
		projectInvesting.setProjectId(project.getProjectId());
		projectInvesting.setBorrowUserId(project.getBorrowUserId());
		projectInvesting.setBorrowHeadImage(project.getBorrowHeadImage());
		projectInvesting.setBorrowNickName(project.getBorrowNickName());
		projectInvesting.setBorrowGender(project.getBorrowGender());
		projectInvesting.setBorrowNiiwooScore(project.getBorrowNiiwooScore());
		projectInvesting.setLoanTimes(project.getLoanTimes());
		projectInvesting.setTitle(project.getTitle());
		projectInvesting.setContractAmount(project.getContractAmount());
		projectInvesting.setInvestedAmount(project.getInvestedAmount());
		projectInvesting.setBorrowRate(project.getBorrowRate());
		projectInvesting.setDeadline(project.getDeadline());
		projectInvesting.setDeadlineUnit(project.getDeadlineUnit());
		projectInvesting.setType(project.getType());
		projectInvesting.setLongitude(project.getLongitude());
		projectInvesting.setLatitude(project.getLatitude());
		projectInvesting.setLoanCity(project.getLoanCity());
		projectInvesting.setLoanArea(project.getLoanArea());
		projectInvesting.setPublishTime(project.getPublishTime());
		projectInvesting.setRepaymentType(project.getRepaymentType());
		projectInvesting.setChannelCode(project.getChannelCode());
        projectInvesting.setCreditType(project.getCreditType());
        projectInvesting.setBorrowerType(project.getBorrowerType());
        projectInvesting.setLoanType(project.getLoanType());

		return projectInvesting;
	}

    /**
     * 更新上标记录状态
     * @param projectPushRecord2Update
     */
    public void updatePushProjectRecordStatus(ProjectPushRecord projectPushRecord2Update){
        ProjectPushRecord projectPushRecord=projectPushRecordMapper.selectByPrimaryKey(projectPushRecord2Update.getId());
        projectPushRecord2Update.setCallNum((byte) (projectPushRecord.getCallNum()+1));
        projectPushRecordMapper.updateByPrimaryKeySelective(projectPushRecord2Update);
    }

    /**
     * 更新上标记录状态
     * @param pushProjectRecordId

     */
    public void deletePushProjectRecordById(Long pushProjectRecordId){
        projectPushRecordMapper.deleteByPrimaryKey(pushProjectRecordId);
    }

    /**
     * 还款服务委托书生成
     * @param userId
     * @param projectId
     */
    public void fadadaWithholdContractSign(String userId,Long projectId){
        String logHead = "SpeedLoanService.fadadaWithholdContractSign userId="+userId+",projectId="+projectId+" ";
        log.info(logHead+"start");
        WithholdContractSignMQDTO withholdContractSignMQDTO = new WithholdContractSignMQDTO();
        withholdContractSignMQDTO.setUserId(userId);
        withholdContractSignMQDTO.setProjectId(projectId);
        log.info(logHead+"withholdContractSignMQDTO="+JSON.toJSONString(withholdContractSignMQDTO));
        rabbitTemplate.convertAndSend(MqConstant.FADADA_CONTRACT_EXCHANGE, MqConstant.FADADA_WITHHOLD_CONTRACT_ROUTE, withholdContractSignMQDTO);
        log.info(logHead+"end");
    }

    /**
     * 根据标的ID查询借款设备信息
     * @param projectId
     * @return
     */
    public ProjectLoanDeviceInfo queryLoanDeviceInfoByProjectId(Long projectId){
        return projectLoanDeviceInfoMapper.selectByPrimaryKey(projectId);
    }

    public List<Project> selectReturnTimeoutProject(Integer timeoutDeadline){
        return projectMapper.selectReturnTimeoutProjectList(timeoutDeadline);
    }

    private SpeedLoanService getSelfProxy() {
        return (SpeedLoanService) AopContext.currentProxy();
    }

    /**
     * 更新最终审核状态
     * @param projectId
     * @param finalAuditResultEnum
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void updateFinalAuditResult(Long projectId,FinalAuditResultEnum finalAuditResultEnum){
        Project project2Update=new Project();
        project2Update.setProjectId(projectId);
        project2Update.setFinalAuditResult(finalAuditResultEnum.getResult());

        projectMapper.updateByPrimaryKeySelective(project2Update);
    }

    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void toManualAudit(Project project) {
    	ProjectTypeEnum projectType = ProjectTypeEnum.getEnum(project.getType());
    	switch (projectType) {
    	// 人工审核-初审
    	case CARD_NIU_LOAN: //卡易借(卡牛)
    	case SOCIAL_SECURITY_LOAN: //社保借
    	case CREDIT_CARD_LOAN: //信用卡借
    	case CONSUME_LOAN: //消费借    		
    		((SpeedLoanService) AopContext.currentProxy()).updateProjectStatus(project.getProjectId(), null, ProjectSubStatusEnum.CHECKING_MANUAL_FIRST);
    		break;
    		
		// 自动审核-人工审核
    	case PERSONAL_SPEEDLOAN: //极速借个人
    	case ORG_SPEEDLOAN: //极速借机构
    	case NIIWOO_CLOUD_LOAN: //你我云贷
    	case SMALL_LOAN: //小易借
    	case ORG_SPEEDLOAN_NEW: //极速借机构
		default:
    		((SpeedLoanService) AopContext.currentProxy()).updateProjectStatus(project.getProjectId(), null, ProjectSubStatusEnum.CHECKING_AUTO_MANUAL);
    		break;
    	}
    	
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public void afterCommit() {
                addAuditWorkTask(project);
            }
        });
    }

    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void toRequestAutoAuditModel(SpeedLoanCreditAuditRequest speedLoanCreditAuditRequest) {
        ((SpeedLoanService) AopContext.currentProxy()).updateProjectStatus(Long.valueOf(speedLoanCreditAuditRequest.getProjectId()), null, ProjectSubStatusEnum.CHECKING_LOAN_FAKE_PASS);

        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public void afterCommit() {
                try {
                    CompletableFuture<AgainstFakeResponse> completableFuture =null;
                    if(isNoZhiMa()) {
                        log.info("借款反欺诈回调,标的ID={},发起天称信审要点去芝麻模型请求,请求参数={}.", speedLoanCreditAuditRequest.getProjectId(), speedLoanCreditAuditRequest);
                        completableFuture = tianchengAgainstFakeService.speedLoanCreditAuditNoZHIMA(speedLoanCreditAuditRequest);
                    }else{
                        log.info("借款反欺诈回调,标的ID={},发起天称信审要点请求,请求参数={}.", speedLoanCreditAuditRequest.getProjectId(), speedLoanCreditAuditRequest);
                        completableFuture = tianchengAgainstFakeService.speedLoanCreditAudit(speedLoanCreditAuditRequest);
                    }
                    AgainstFakeResponse againstFakeResponse = completableFuture.get();
                    log.info("借款反欺诈回调,标的ID={},发起天称信审要点请求,响应结果={}.", speedLoanCreditAuditRequest.getProjectId(), againstFakeResponse);
                } catch (Exception e) {
                    log.error("借款反欺诈回调,标的ID={},发生系统异常,错误信息={}", speedLoanCreditAuditRequest.getProjectId(), e);
                    return;
                }
            }
        });
    }

    /**
     * 是否去芝麻模型
     *
     * @return
     */
    public boolean isNoZhiMa() {
        return tradeConfigService.selectTradeConfigByEmun(TradeConfigEnum.SESAMEAUTHORIZATIONSTATUS).equals("0");
    }

    /**
     * 发标信用额度变更消息推送
     *
     * @param userId
     */
    private void sendMsgForAviAmountChange(String userId) {
        log.info("sendMsgForAviAmountChangeLoanApply:" + userId);
        try {
            activityEventService.sendMsgForAviAmountChange(userId, UsableCreditChangeTypeEventEnum.APPLY);
        } catch (Exception e) {
            log.error("sendMsgForAviAmountChangeLoanApply:" + userId, e);
        }
    }

    /**
     * 运营投资加息活动处理
     * 
     * @param project
     * @param project2Update
     */
    private void projectRaiseRateHandle(Project project, Project project2Update) {
    	try {
	    	AddInterestRateConfigRequestDTO addInterestRateConfigRequestDTO = new AddInterestRateConfigRequestDTO();
	    	addInterestRateConfigRequestDTO.setOrgId(project.getOrgId());
	    	addInterestRateConfigRequestDTO.setDeadline(project.getDeadline());
	    	addInterestRateConfigRequestDTO.setDeadlineUnit(project.getDeadlineUnit());
            addInterestRateConfigRequestDTO.setChannelCode(project.getChannelCode());
	    	addInterestRateConfigRequestDTO.setRepaymentType(project.getRepaymentType());
	    	log.info("###发布借款###查询是否有符合条件的投资加息活动，ProjectId:{}, 请求参数：{}", project.getProjectId(), JSONObject.toJSONString(addInterestRateConfigRequestDTO));
	    	AddInterestRateConfigResponseDTO addInterestRateConfigResponseDTO = projectInvestPrizeService.getAddInterestRateConfig(addInterestRateConfigRequestDTO);
	    	log.info("###发布借款###查询是否有符合条件的投资加息活动，ProjectId:{}, 返回结果：{}", project.getProjectId(), JSONObject.toJSONString(addInterestRateConfigResponseDTO));
	    	
	    	if (null == addInterestRateConfigResponseDTO || null == addInterestRateConfigResponseDTO.getId()) return;
	    	
	    	// 返回活动更新活动ID以及活动利率
	    	project2Update.setActivityId(addInterestRateConfigResponseDTO.getId());
	    	project2Update.setActivityRaiseRate(addInterestRateConfigResponseDTO.getAddInterestRate());
    	} catch (Exception e) {
    		log.error("推标,标的ID={},查询运营投资加息活动异常.", project.getProjectId(), e);
		}
    }
}
